/**
  ******************************************************************************
  * @file    sym32l010_hal_i2c.c
  * @author  AE Team
  * @version 1.0.3
  * @date    2024-05-28
  * @brief   I2C HAL module driver.
  *
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2024 SIYIMicro.
  * All rights reserved.</center></h2>
  *
  *
  ******************************************************************************
  */


/******************************************************************************/
/* Include files                                                              */
/******************************************************************************/
#include "sym32l010_hal_i2c.h"
#include "sym32l010_hal_systick.h"

/*******************************************************************************
  * @brief  等待I2Cx_CR_SI中断标志，直到超时
  * @param  hI2c       : I2C句柄指针，指向包含I2C配置、通信参数的结构体
  * @param  TimeOut    : 等待的超时时间，以ms为单位。
  *                      0代表一直等待，没有超时功能
  * @param  TickStart  : TimeOut开始时刻
  * @retval status     : HAL_OK      表示标志已置位
  *                      HAL_TIMEOUT 表示等待过程中超时
  */
static HAL_StatusTypeDef I2C_WaitSIUntilTimeout(I2C_HandleTypeDef *hI2c, uint32_t TimeOut, uint32_t TickStart)
{
    do
    {
        /* Check for the TimeOut */
        if (TimeOut && ((HAL_GetTick() - TickStart) > TimeOut))
        {
            return HAL_TIMEOUT;
        }
    } while (HAL_I2C_GET_FLAG(hI2c) == 0x00);
    return HAL_OK;
}


/*******************************************************************************
  * @brief  等待发送STOP流程完成标志，直到超时
  * @param  hI2c       : I2C句柄指针，指向包含I2C配置、通信参数的结构体
  * @param  TimeOut    : 等待的超时时间，以ms为单位。
  *                      0代表一直等待，没有超时功能
  * @param  TickStart  : TimeOut开始时刻
  * @retval status     : HAL_OK      表示标志已置位
  *                      HAL_TIMEOUT 表示等待过程中超时
  */
HAL_StatusTypeDef I2C_WaitSTOUntilTimeout(I2C_HandleTypeDef *hI2c, uint32_t TimeOut, uint32_t TickStart)
{
    do
    {
        /* Check for the TimeOut */
        if (TimeOut && ((HAL_GetTick() - TickStart) > TimeOut))
        {
            return HAL_TIMEOUT;
        }
    } while (hI2c->Instance->CR & I2Cx_CR_STO_Msk);
    return HAL_OK;
}


/*******************************************************************************
  * @brief  发送Start或者Restart，直到发送成功或者TimeOut
  * @param  hI2c       : I2C句柄指针，指向包含I2C配置、通信参数的结构体
  * @param  TimeOut    : 等待的超时时间，以ms为单位。
  *                      0代表一直等待，没有超时功能
  * @param  TickStart  : TimeOut开始时刻
  * @retval status     : HAL_OK      表示发送成功
  *                      HAL_ERROR   表示总线出错
  *                      HAL_TIMEOUT 表示发送过程中超时
  */
static HAL_StatusTypeDef I2C_WaitSendStartTimeOut(I2C_HandleTypeDef *hI2c, uint32_t TimeOut, uint32_t TickStart)
{
    HAL_StatusTypeDef status = HAL_TIMEOUT;
    REGBITS_SET(hI2c->Instance->CR, I2Cx_CR_STA_Msk);                 // SendStart

    while (I2C_WaitSIUntilTimeout(hI2c, TimeOut, TickStart) == HAL_OK)// TimeOut等待SI中断标志
    {
        uint8_t tmp8 = hI2c->Instance->STAT;
        if ((tmp8 == 0x08) || (tmp8 == 0x10))                         // 成功发送Start
        {
            status = HAL_OK;
            break;
        }
        if (tmp8 == 0x00)                                             // I2C总线出错
        {
            hI2c->ErrorCode = I2C_ERROR_BUS;
            status = HAL_ERROR;
            break;
        }
        else
        {
            REGBITS_CLR(hI2c->Instance->CR, I2Cx_CR_SI_Msk);          // 更新I2C状态
        }
    }
    REGBITS_CLR(hI2c->Instance->CR, I2Cx_CR_STA_Msk);

    if (status != HAL_TIMEOUT)
    {
        return status;
    }
    else
    {
        hI2c->ErrorCode = I2C_ERROR_SENDSTART_TIMEOUT;
        status = HAL_TIMEOUT;
        return status;
    }
}


/*******************************************************************************
  * @brief  I2C 错误处理函数
  * @param  hI2c       : I2C句柄指针，指向包含I2C配置、通信参数的结构体
  * @retval status     : HAL_OK      表示无错误
  *                      HAL_TIMEOUT 表示超时错误
  *                      HAL_ERROR   表示状态错误
  */
static HAL_StatusTypeDef HAL_I2C_DealError(I2C_HandleTypeDef *hI2c)
{
    I2C_ErrorTypeDef code = hI2c->ErrorCode;

    switch (code)
    {
        case I2C_ERROR_OK:
        {
            hI2c->XferState = HAL_OK;
            return HAL_OK;
        }
        case I2C_ERROR_BUS:                                           // 总线错误
        {
            HAL_I2C_DISABLE(hI2c);
            HAL_I2C_ENABLE(hI2c);
            REGBITS_CLR(hI2c->Instance->CR, I2Cx_CR_AA_Msk);
            hI2c->XferState = HAL_ERROR;
            break;
        }

        // 主机Error处理
        case I2C_ERROR_MASTER_LOS_ARB:                                // 主机丢失仲裁
        {
            hI2c->XferState = HAL_ERROR;
            break;
        }
        case I2C_ERROR_MASTER_LOS_ARB_S:                              // 主机丢失仲裁同时已作为从机发送了应答
        {
            hI2c->XferState = HAL_ERROR;
            return hI2c->XferState;                                   // 等待后续作为从机处理
        }
        case I2C_ERROR_MASTER_TRANSMIT_DATA_REMAIN:
        case I2C_ERROR_MASTER_SENDADDR_NACK:                          // 发送地址时无设备应答
        {
            REGBITS_SET(hI2c->Instance->CR, I2Cx_CR_STO_Msk);
            break;
        }
        case I2C_ERROR_MASTER_RECEIVE_TIMEOUT:                        // 主机超时
        case I2C_ERROR_MASTER_TRANSMIT_TIMEOUT:
        case I2C_ERROR_SENDSTART_TIMEOUT:
        {
            HAL_I2C_DISABLE(hI2c);
            HAL_I2C_ENABLE(hI2c);
            hI2c->XferState = HAL_TIMEOUT;
            break;
        }
        case I2C_ERROR_MASTER_STATUS:                                 // 主机状态错误
        {
            HAL_I2C_DISABLE(hI2c);
            HAL_I2C_ENABLE(hI2c);
            hI2c->XferState = HAL_ERROR;
            break;
        }

        // 从机Error处理
        case I2C_ERROR_SLAVE_RECEIVE_DATA_REMAIN:
        {
            REGBITS_CLR(hI2c->Instance->CR, I2Cx_CR_AA_Msk);
            hI2c->XferState = HAL_ERROR;
            break;
        }
        case I2C_ERROR_SLAVE_RECEIVE_RESTART:
        {
            hI2c->XferState = HAL_ERROR;
            HAL_I2C_CLR_FLAG(hI2c);                                   // 清除Flag标志
            return hI2c->XferState;
        }
        case I2C_ERROR_SLAVE_STATUS:
        case I2C_ERROR_SLAVE_TRANSMIT_DATA_OV:
        case I2C_ERROR_SLAVE_TRANSMIT_DATA_REMAIN:
        {
            REGBITS_SET(hI2c->Instance->CR, I2Cx_CR_STO_Msk);         // 回到未被寻址从机状态
            hI2c->XferState = HAL_ERROR;
            break;
        }
        case I2C_ERROR_SLAVE_RECEIVE_TIMEOUT:
        case I2C_ERROR_SLAVE_TRANSMIT_TIMEOUT:
        {
            REGBITS_SET(hI2c->Instance->CR, I2Cx_CR_STO_Msk);         // 回到未被寻址从机状态
            hI2c->XferState = HAL_TIMEOUT;
            break;
        }
        default:
        {
            hI2c->XferState = HAL_ERROR;
            break;
        }
    }
    REGBITS_CLR(hI2c->Instance->CR, I2Cx_CR_AA_Msk);
    HAL_I2C_CLR_FLAG(hI2c);                                           // 清除Flag标志
    return hI2c->XferState;
}


/*******************************************************************************
  * @brief  初始化I2C模块
  * @param  hI2c       : I2C句柄指针，指向包含I2C配置、通信参数的结构体
  * @retval HAL status : HAL_OK    表示初始化成功
  *                      HAL_ERROR 表示初始化失败
  * @note   需通过APBENx寄存器使能I2Cx的时钟后，才可调用该函数
  *         需要在I2Cx禁止的时候才可调用该函数
  */
HAL_StatusTypeDef HAL_I2C_Init(I2C_HandleTypeDef *hI2c)
{
    if (hI2c == NULL)
    {
        return HAL_ERROR;
    }

    hI2c->Instance->CR    = (uint32_t)hI2c->Init.SclInSrc | (uint32_t)hI2c->Init.SdaInSrc;
    hI2c->Instance->BRR   = hI2c->Init.PclkFreq / 8 / hI2c->Init.SclFreq - 1;
    hI2c->Instance->ADDR0 = hI2c->Init.OwnAddr0 | (uint32_t)hI2c->Init.GeneralCall;
    hI2c->Instance->ADDR1 = hI2c->Init.OwnAddr1;
    hI2c->Instance->ADDR2 = hI2c->Init.OwnAddr2;

    if (hI2c->Init.WorkMode == I2C_WORKMODE_MASTER)                   // 主机模式
    {
        hI2c->Instance->BRREN = 0x01;
        if (hI2c->Instance->BRR <= 9)
        {
            REGBITS_SET(hI2c->Instance->CR, I2Cx_CR_FLT_Msk);
        }
    }
    else                                                              // 从机模式
    {
        if (hI2c->Instance->BRR <= 4)                                 // fpclk / fscl <= 40
        {
            REGBITS_SET(hI2c->Instance->CR, I2Cx_CR_FLT_Msk);
        }
    }

    REGBITS_SET(hI2c->Instance->CR, I2Cx_CR_EN_Msk);

    return HAL_OK;
}


/*******************************************************************************
  * @brief  I2C 模块反初始化
  * @param  hI2c       : I2C句柄指针，指向包含I2C配置、通信参数的结构体
  * @retval HAL status : HAL_OK    表示反初始化成功
  *                      HAL_ERROR 表示反初始化失败
  */
HAL_StatusTypeDef HAL_I2C_DeInit(I2C_HandleTypeDef *hI2c)
{
    if (hI2c == NULL)
    {
        return HAL_ERROR;
    }

    REGBITS_CLR(SYM_SYSCTRL->APBRST2, SYSCTRL_APBRST2_I2C1_Msk);
    REGBITS_SET(SYM_SYSCTRL->APBRST2, SYSCTRL_APBRST2_I2C1_Msk);

    return HAL_OK;
}


/*******************************************************************************
  * @brief  作为主机向I2C总线发送START位
  * @param  I2Cx       : I2C模块名称  @arg I2C1
  * @retval HAL status : HAL_OK      表示向总线发送START位成功
  *                      HAL_ERROR   表示向总线发送START位失败，查询I2Cx->STAT以获取失败原因
  */
HAL_StatusTypeDef HAL_I2C_Master_SendStart(I2C_TypeDef *I2Cx)
{
    if (I2Cx->STAT != 0xF8)
    {
        REGBITS_SET(I2Cx->CR, I2Cx_CR_STA_Msk);
        REGBITS_CLR(I2Cx->CR, I2Cx_CR_SI_Msk);
    }
    else
    {
        REGBITS_SET(I2Cx->CR, I2Cx_CR_STA_Msk);
    }

    while ((I2Cx->CR & I2Cx_CR_SI_Msk) == 0x00) { ; }
    REGBITS_CLR(I2Cx->CR, I2Cx_CR_STA_Msk);

    if ((I2Cx->STAT == 0x08) || (I2Cx->STAT == 0x10))
    {
        return HAL_OK;
    }

    return HAL_ERROR;
}


/*******************************************************************************
  * @brief  作为主机向I2C总线发送ReSTART位
  * @param  I2Cx       : I2C模块名称  @arg I2C1
  * @retval HAL status : HAL_OK     表示向总线发送ReSTART位成功
  *                      HAL_ERROR  表示向总线发送ReSTART位失败，查询I2Cx->STAT以获取失败原因
  */
HAL_StatusTypeDef HAL_I2C_Master_SendReStart(I2C_TypeDef *I2Cx)
{
    return HAL_I2C_Master_SendStart(I2Cx);
}


/*******************************************************************************
  * @brief  作为主机向I2C总线发送STOP位
  * @param  I2Cx       : I2C模块名称  @arg I2C1
  * @retval HAL status : HAL_OK      表示向总线发送STOP位成功
  *                      HAL_ERROR   表示向总线发送STOP位失败，查询I2Cx->STAT以获取失败原因
  */
HAL_StatusTypeDef HAL_I2C_Master_SendStop(I2C_TypeDef *I2Cx)
{
    REGBITS_SET(I2Cx->CR, I2Cx_CR_STO_Msk);
    REGBITS_CLR(I2Cx->CR, I2Cx_CR_SI_Msk);

    while (I2Cx->CR & I2Cx_CR_STO_Msk) { ; }

    return HAL_OK;
}


/*******************************************************************************
  * @brief  作为主机向I2C总线发送一个字节
  * @param  I2Cx       : I2C模块名称  @arg I2C1
  * @param  TxByte     : 待发送到总线的上数据
  * @retval HAL status : HAL_OK     表示向总线发送数据成功
  *                      HAL_ERROR  表示向总线发送数据失败，查询I2Cx->STAT以获取失败原因
  */
HAL_StatusTypeDef HAL_I2C_Master_SendByte(I2C_TypeDef *I2Cx, uint8_t TxByte)
{
    I2Cx->DR = TxByte;
    REGBITS_CLR(I2Cx->CR, I2Cx_CR_SI_Msk);
    while ((I2Cx->CR & I2Cx_CR_SI_Msk) == 0x00) { ; }
    REGBITS_CLR(I2Cx->CR, I2Cx_CR_STA_Msk);

    if ((I2Cx->STAT == 0x18) || (I2Cx->STAT == 0x28) || (I2Cx->STAT == 0x40))
    {
        return HAL_OK;
    }

    return HAL_ERROR;
}


/*******************************************************************************
  * @brief  作为主机从I2C总线接收一个字节并发送ACK/NAK
  * @param  I2Cx    : I2C模块名称  @arg I2C1
  * @param  AckOrNak: 接收完成后发送到总线上的ACK/NAK
  *                   I2C_RESPONSE_ACK / I2C_RESPONSE_NAK
  * @retval 从总线接收到的一字节数据
  */
uint8_t HAL_I2C_Master_RecvByte(I2C_TypeDef *I2Cx, I2C_ResponseTypeDef AckOrNak)
{
    REGBITS_MODIFY(I2Cx->CR, I2Cx_CR_AA_Msk, (uint32_t)AckOrNak);
    REGBITS_CLR(I2Cx->CR, I2Cx_CR_SI_Msk);
    while ((I2Cx->CR & I2Cx_CR_SI_Msk) == 0x00) { ; }

    return I2Cx->DR;
}


/*******************************************************************************
  * @brief  检查I2C设备是否处于空闲状态
  * @param  hI2c       : I2C句柄指针，指向包含I2C配置、通信参数的结构体
  * @param  DevAddress : 目标设备地址 （b7-b1, 0）
  * @param  Trials     : 检查的次数, 0表示一直进行检查直到设备READY
  * @param  TimeOut    : 每执行一次检查的超时时间，若某次检查超时则返回错误
  * @retval status     : HAL_OK      表示设备空闲
  *                      HAL_BUSY    表示设备忙
  *                      HAL_ERROR   表示设备或总线出错
  *                      HAL_TIMEOUT 表示等待超时
  *
  * @note   TimeOut说明: 主机发生TimeOut时该函数会重新使能I2C模块并返回HAL_TIMEOUT,
  *                      主机I2C重新使能会立即释放总线
  */
HAL_StatusTypeDef HAL_I2C_Master_IsDeviceReady(I2C_HandleTypeDef *hI2c, uint16_t DevAddress, uint32_t Trials, uint32_t TimeOut)
{
    uint32_t tickStart;
    uint32_t I2C_Trials = 0U;
    HAL_StatusTypeDef status = HAL_BUSY;
    hI2c->ErrorCode  = I2C_ERROR_OK;

    if (hI2c == NULL)
    {
        return HAL_ERROR;
    }

    while ((Trials == 0) || (I2C_Trials++ < Trials))
    {
        tickStart = HAL_GetTick();

        if (HAL_OK != I2C_WaitSendStartTimeOut(hI2c, TimeOut, tickStart))   // 如果出错则ErrorCode改变
        {
            break;
        }

        hI2c->Instance->DR = DevAddress;                              // 发送SLA+W
        REGBITS_CLR(hI2c->Instance->CR, I2Cx_CR_SI_Msk);
        if (HAL_OK != I2C_WaitSIUntilTimeout(hI2c, TimeOut, tickStart)) // TimeOut等待SI中断标志
        {
            hI2c->ErrorCode = I2C_ERROR_MASTER_TRANSMIT_TIMEOUT;
            break;
        }
        uint8_t tmp8 = hI2c->Instance->STAT;
        if (tmp8 == 0x18)                                             // 收到ACK
        {
            status = HAL_OK;
            break;
        }
        else if (tmp8 == 0x20)                                        // 收到NACK
        {
            status = HAL_BUSY;
            continue;
        }
        else
        {
            if (tmp8 == 0x00)
            {
                hI2c->ErrorCode = I2C_ERROR_BUS;
                break;
            }
            else
            {
                hI2c->ErrorCode = I2C_ERROR_MASTER_STATUS;
                break;
            }
        }
    }

    // 错误处理
    if (I2C_ERROR_OK != hI2c->ErrorCode)
    {
        return HAL_I2C_DealError(hI2c);
    }
    else
    {
        REGBITS_SET(hI2c->Instance->CR, I2Cx_CR_STO_Msk);
        REGBITS_CLR(hI2c->Instance->CR, I2Cx_CR_SI_Msk);
        hI2c->XferState = status;
        return status;
    }
}


/*******************************************************************************
  * @brief  作为主机采用查询方式向从设备写入多个字节
  * @param  hI2c       : I2C句柄指针，指向包含I2C配置、通信参数的结构体
  * @param  DevAddress : 目标设备地址 （b7-b1, 0）
  * @param  pData      : 待输数据的指针
  * @param  Size       : 待发送数据的字节数量
  * @param  TimeOut    : 等待发送数据的超时时间，以ms为单位。
  *                      0代表一直等待，没有超时功能
  * @retval status     : HAL_OK      表示向Slave设备发送数据成功
  *                      HAL_TIMEOUT 表示发送数据时超时,查询I2Cx->STAT以获取超时原因
  *                      HAL_ERROR   表示向Slave设备发送数据失败,查询I2Cx->STAT以获取失败原因
  *
  * @note   TimeOut说明: 主机发生TimeOut时该函数会重新使能I2C模块并返回HAL_TIMEOUT,
  *                      主机I2C重新使能会立即释放总线
  */
HAL_StatusTypeDef HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hI2c, uint16_t DevAddress, uint8_t *pData, uint32_t Size, uint32_t TimeOut)
{
    uint8_t isSendDevAddrFlag = 1;
    uint32_t tickStart = HAL_GetTick();

    if (hI2c == NULL)
    {
        return HAL_ERROR;
    }

    hI2c->pBuffPtr   = pData;
    hI2c->XferSize   = Size;
    hI2c->XferCount  = Size;
    hI2c->XferMode   = I2C_XFERMODE_TRANSMIT;
    hI2c->DevAddress = DevAddress;
    hI2c->XferState  = HAL_BUSY;
    hI2c->ErrorCode  = I2C_ERROR_OK;

    if (HAL_OK != I2C_WaitSendStartTimeOut(hI2c, TimeOut, tickStart))
    {
        return HAL_I2C_DealError(hI2c);
    }

    while (hI2c->XferCount > 0)                                       // 发送地址和数据
    {
        if (isSendDevAddrFlag)                                        // 发送的是地址
        {
            isSendDevAddrFlag = 0;
            hI2c->Instance->DR = DevAddress | 0x00UL;
        }
        else                                                          // 发送的是数据
        {
            hI2c->Instance->DR = *hI2c->pBuffPtr;
            hI2c->pBuffPtr++;
            hI2c->XferCount--;
        }
        REGBITS_CLR(hI2c->Instance->CR, I2Cx_CR_SI_Msk);              // 开始发送

        if (HAL_OK != I2C_WaitSIUntilTimeout(hI2c, TimeOut, tickStart))   // TimeOut等待SI中断标志
        {
            hI2c->ErrorCode = I2C_ERROR_MASTER_TRANSMIT_TIMEOUT;
            break;
        }

        switch (hI2c->Instance->STAT)
        {
            case 0x18:                                                // 已收到应答
            case 0x28:
                continue;
            case 0x20:
            case 0x30:                                                // 未收到应答
                if (hI2c->XferCount != 0)
                {
                    hI2c->ErrorCode = I2C_ERROR_MASTER_TRANSMIT_DATA_REMAIN;
                }
                break;
            case 0x38:                                                // 丢失仲裁
                hI2c->ErrorCode = I2C_ERROR_MASTER_LOS_ARB;
                break;
            case 0x00:                                                // 总线错误
                hI2c->ErrorCode = I2C_ERROR_BUS;
                break;
            default:
                hI2c->ErrorCode = I2C_ERROR_MASTER_STATUS;
                break;
        }
        if (I2C_ERROR_OK != hI2c->ErrorCode)                          // 检查状态
        {
            break;
        }
    }

    if (I2C_ERROR_OK != hI2c->ErrorCode)
    {
        return HAL_I2C_DealError(hI2c);
    }
    else
    {
        if (hI2c->XferDone == I2C_XFERDONE_STOP)                      // 传输成功是否发送STOP
        {
            REGBITS_SET(hI2c->Instance->CR, I2Cx_CR_STO_Msk);
            REGBITS_CLR(hI2c->Instance->CR, I2Cx_CR_AA_Msk);
            REGBITS_CLR(hI2c->Instance->CR, I2Cx_CR_SI_Msk);
        }
        hI2c->XferState = HAL_OK;
        return HAL_OK;
    }
}


/*******************************************************************************
  * @brief  作为主机采用查询方式向从Slave设备读出多个字节
  * @param  hI2c       : I2C句柄指针，指向包含I2C配置、通信参数的结构体
  * @param  DevAddress : 从设备地址 （b7-b1,0）
  * @param  pData      : 存储从总线接收到的数据的指针
  * @param  Size       : 待接收的数据的数量
  * @param  TimeOut    : 等待接收数据的超时时间，以ms为单位。
  *                      0代表一直等待，没有超时功能
  * @retval status     : HAL_OK      表示从Slave设备读取数据成功
  *                      HAL_TIMEOUT 表示从Slave设备读取数据时超时，查询I2Cx->STAT以获取超时原因
  *                      HAL_ERROR   表示从Slave设备读取数据失败，查询I2Cx->STAT以获取失败原因
  *
  * @note   TimeOut说明: 主机发生TimeOut时该函数会重新使能I2C模块并返回HAL_TIMEOUT,
  *                      主机I2C重新使能会立即释放总线,若TimeOut时I2C正在接收数据过程,
  *                      下次操作I2C时,I2C将继续数据传输,若该操作是置位STA,可等待SI置位后清除SI,
  *                      I2C会在某个时机发送Start,以达到发送Restart从而恢复数据传输状态的效果
  */
HAL_StatusTypeDef HAL_I2C_Master_Receive(I2C_HandleTypeDef *hI2c, uint16_t DevAddress, uint8_t *pData, uint32_t Size, uint32_t TimeOut)
{
    uint32_t tickStart = HAL_GetTick();
    I2C_ResponseTypeDef RespAck = I2C_RESPONSE_ACK;

    if (hI2c == NULL)
    {
        return HAL_ERROR;
    }

    hI2c->DevAddress = DevAddress;
    hI2c->pBuffPtr   = pData;
    hI2c->XferSize   = Size;
    hI2c->XferCount  = Size;
    hI2c->XferMode   = I2C_XFERMODE_RECEIVE;
    hI2c->XferState  = HAL_BUSY;
    hI2c->ErrorCode  = I2C_ERROR_OK;

    // 发送Start
    if (HAL_OK != I2C_WaitSendStartTimeOut(hI2c, TimeOut, tickStart))
    {
        return HAL_I2C_DealError(hI2c);
    }

    // 发送地址
    hI2c->Instance->DR = DevAddress | 0x01UL;                         // 发送SLA+R
    REGBITS_CLR(hI2c->Instance->CR, I2Cx_CR_SI_Msk);                  // 开始发送
    if (HAL_OK != I2C_WaitSIUntilTimeout(hI2c, TimeOut, tickStart))   // TimeOut等待SI中断标志
    {
        hI2c->ErrorCode = I2C_ERROR_MASTER_RECEIVE_TIMEOUT;
        return HAL_I2C_DealError(hI2c);
    }

    uint8_t tmp8 = hI2c->Instance->STAT;
    switch (tmp8)
    {
        case 0x40:
            hI2c->ErrorCode = I2C_ERROR_OK;
            break;
        case 0x48:
            hI2c->ErrorCode = I2C_ERROR_MASTER_SENDADDR_NACK;         // 收到NACK
            break;
        case 0x38:                                                    // 丢失仲裁
            hI2c->ErrorCode = I2C_ERROR_MASTER_LOS_ARB;
            break;
        default:
            hI2c->ErrorCode = I2C_ERROR_MASTER_STATUS;
            break;
    }
    if (I2C_ERROR_OK != hI2c->ErrorCode)
    {
        return HAL_I2C_DealError(hI2c);
    }

    // Receive Data
    while (hI2c->XferCount > 0)
    {
        RespAck = (hI2c->XferCount > 1) ? I2C_RESPONSE_ACK : I2C_RESPONSE_NAK;
        REGBITS_MODIFY(hI2c->Instance->CR, I2Cx_CR_AA_Msk, RespAck);  // 应答NACK或者ACK
        REGBITS_CLR(hI2c->Instance->CR, I2Cx_CR_SI_Msk);              // 开始接收

        if (HAL_OK != I2C_WaitSIUntilTimeout(hI2c, TimeOut, tickStart)) // TimeOut等待SI中断标志
        {
            hI2c->ErrorCode = I2C_ERROR_MASTER_RECEIVE_TIMEOUT;
            break;
        }
        tmp8 = hI2c->Instance->STAT;
        if ((tmp8 == 0x50) || ((tmp8 == 0x58) && (hI2c->XferCount == 1)))
        {
            *hI2c->pBuffPtr = hI2c->Instance->DR;
            hI2c->pBuffPtr++;
            hI2c->XferCount--;
            continue;
        }
        else
        {
            if (tmp8 == 0x00)                                         // 总线错误
            {
                hI2c->ErrorCode = I2C_ERROR_BUS;
            }
            else if (tmp8 == 0x38)                                    // 丢失仲裁
            {
                hI2c->ErrorCode = I2C_ERROR_MASTER_LOS_ARB;
            }
            // else if ((tmp8 == 0x68) || (tmp8 == 0xB0))
            // {
            //     hI2c->ErrorCode = I2C_ERROR_MASTER_LOS_ARB_S;
            // }
            else
            {
                hI2c->ErrorCode = I2C_ERROR_MASTER_STATUS;
            }
            break;
        }
    }

    // 错误处理
    if (I2C_ERROR_OK != hI2c->ErrorCode)
    {
        return HAL_I2C_DealError(hI2c);
    }
    else
    {
        if (hI2c->XferDone == I2C_XFERDONE_STOP)                      // Send Stop
        {
            REGBITS_SET(hI2c->Instance->CR, I2Cx_CR_STO_Msk);
            REGBITS_CLR(hI2c->Instance->CR, I2Cx_CR_AA_Msk);
            REGBITS_CLR(hI2c->Instance->CR, I2Cx_CR_SI_Msk);
        }
        return HAL_OK;
    }
}


/*******************************************************************************
  * @brief  作为主机采用中断方式向从设备写入多个字节
  * @param  hI2c       : I2C句柄指针，指向包含I2C配置、通信参数的结构体
  * @param  DevAddress : 从设备地址 （b7-b1,0）
  * @param  pData      : 待传输数据的指针
  * @param  Size       : 待传输数据的字节数量
  * @retval HAL status : HAL_OK    表示启动中断发送数据成功
  *                      HAL_ERROR 表示启动中断发送数据失败
  */
HAL_StatusTypeDef HAL_I2C_Master_Transmit_IT(I2C_HandleTypeDef *hI2c, uint16_t DevAddress, uint8_t *pData, uint32_t Size)
{
    if (hI2c == NULL)
    {
        return HAL_ERROR;
    }

    hI2c->DevAddress = DevAddress;
    hI2c->pBuffPtr   = pData;
    hI2c->XferSize   = Size;
    hI2c->XferCount  = Size;
    hI2c->XferMode   = I2C_XFERMODE_TRANSMIT;
    hI2c->XferState  = HAL_BUSY;

    if (hI2c->Instance->STAT != 0xF8)
    {
        REGBITS_SET(hI2c->Instance->CR, I2Cx_CR_STA_Msk);
        REGBITS_CLR(hI2c->Instance->CR, I2Cx_CR_SI_Msk);
    }
    else
    {
        REGBITS_SET(hI2c->Instance->CR, I2Cx_CR_STA_Msk);             // 在START完成的中断服务中进行发送
    }

    NVIC_ClearPendingIRQ(I2C1_IRQn);
    NVIC_EnableIRQ(I2C1_IRQn);

    return HAL_OK;
}


/*******************************************************************************
  * @brief  在中断服务程序中发送I2C数据
  * @param  hI2c : I2C句柄指针，指向包含I2C配置、通信参数的结构体
  * @retval None
  */
static void HAL_I2C_Master_Transmit_IT_CallBack(I2C_HandleTypeDef *hI2c)
{
    switch (hI2c->Instance->STAT)
    {
        case 0x08:                                                    // Start
        case 0x10:                                                    // Resetart
        {
            REGBITS_CLR(hI2c->Instance->CR, I2Cx_CR_STA_Msk);
            hI2c->Instance->DR = hI2c->DevAddress;                    // Transmit Mode
            break;
        }
        case 0x18:                                                    // send SLA+W, Recv ACK
        case 0x28:                                                    // send DR,    Recv ACK
        {
            if (hI2c->XferCount > 0)                                  // 数据尚未发送完成
            {
                hI2c->Instance->DR = *hI2c->pBuffPtr;
                hI2c->pBuffPtr++;
                hI2c->XferCount--;
            }
            else                                                      // 数据已发送完成
            {
                hI2c->XferState = HAL_OK;
                if (hI2c->XferDone == I2C_XFERDONE_STOP)
                {
                    REGBITS_SET(hI2c->Instance->CR, I2Cx_CR_STO_Msk);
                    REGBITS_CLR(hI2c->Instance->CR, I2Cx_CR_SI_Msk);
                }
                //if (hI2c->Instance == SYM_I2C1)
                {
                    NVIC_DisableIRQ(I2C1_IRQn);
                }
                return;
            }
            break;
        }
        case 0x20:                                                    // send SLA+W, Recv NACK
        case 0x30:                                                    // send DR,    Recv NACK
        {
            if (hI2c->XferDone == I2C_XFERDONE_STOP)
            {
                REGBITS_SET(hI2c->Instance->CR, I2Cx_CR_STO_Msk);
                REGBITS_CLR(hI2c->Instance->CR, I2Cx_CR_SI_Msk);
            }
            hI2c->XferState = (hI2c->XferCount == 0) ? HAL_OK : HAL_ERROR;
            //if (hI2c->Instance == SYM_I2C1)
            {
                NVIC_DisableIRQ(I2C1_IRQn);
            }
            return;
        }
        default:
        {
            hI2c->XferState = HAL_ERROR;
            break;
        }
    }

    REGBITS_CLR(hI2c->Instance->CR, I2Cx_CR_SI_Msk);
}


/*******************************************************************************
  * @brief  查询待通过中断发送的数据是否发送完成
  * @param  hI2c       : I2C句柄指针，指向包含I2C配置、通信参数的结构体
  * @retval HAL status : HAL_OK    表示成功完成发送
  *                      HAL_BUSY  表示正在发送中
  *                      HAL_ERROR 表示发送失败，查询I2Cx->STAT以获取失败原因
  */
HAL_StatusTypeDef HAL_I2C_Master_Transmit_IT_IsComplete(I2C_HandleTypeDef *hI2c)
{
    return hI2c->XferState;
}


/*******************************************************************************
  * @brief  作为主机采用中断方式从从设备读出多个字节
  * @param  hI2c       : I2C句柄指针，指向包含I2C配置、通信参数的结构体
  * @param  DevAddress : 从设备地址 （b7-b1,0）
  * @param  pData      : 待接收数据的指针
  * @param  Size       : 待接收数据的字节数量
  * @retval HAL status : HAL_OK    表示启动中断接收数据成功
  *                      HAL_ERROR 表示启动中断接收数据失败
  */
HAL_StatusTypeDef HAL_I2C_Master_Receive_IT(I2C_HandleTypeDef *hI2c, uint16_t DevAddress, uint8_t *pData, uint32_t Size)
{
    if (hI2c == NULL)
    {
        return HAL_ERROR;
    }

    hI2c->DevAddress = DevAddress;
    hI2c->pBuffPtr   = pData;
    hI2c->XferSize   = Size;
    hI2c->XferCount  = Size;
    hI2c->XferMode   = I2C_XFERMODE_RECEIVE;
    hI2c->XferState  = HAL_BUSY;

    if (hI2c->Instance->STAT != 0xF8)
    {
        REGBITS_SET(hI2c->Instance->CR, I2Cx_CR_STA_Msk);
        REGBITS_CLR(hI2c->Instance->CR, I2Cx_CR_SI_Msk);
    }
    else
    {
        REGBITS_SET(hI2c->Instance->CR, I2Cx_CR_STA_Msk);             // 在START完成的中断服务中进行读取
    }

    NVIC_ClearPendingIRQ(I2C1_IRQn);
    NVIC_EnableIRQ(I2C1_IRQn);

    return HAL_OK;
}


/*******************************************************************************
  * @brief  在中断服务程序中读取I2C数据
  * @param  hI2c       : I2C句柄指针，指向包含I2C配置、通信参数的结构体
  * @retval None
  */
void HAL_I2C_Master_Receive_IT_CallBack(I2C_HandleTypeDef *hI2c)
{
    switch (hI2c->Instance->STAT)
    {
        case 0x08:                                                    // Start
        case 0x10:                                                    // Restart
        {
            REGBITS_CLR(hI2c->Instance->CR, I2Cx_CR_STA_Msk);
            hI2c->Instance->DR = hI2c->DevAddress | 1;                // Receive Mode
            break;
        }
        case 0x40:                                                    // send SLA+R Done
        {
            hI2c->Instance->CR_f.AA = (hI2c->XferCount > 1) ? 1 : 0;
            break;
        }
        case 0x50:                                                    // Recv DR + ACK
        {
            *hI2c->pBuffPtr = hI2c->Instance->DR;
            hI2c->pBuffPtr++;
            hI2c->XferCount--;
            if (hI2c->XferCount == 1)
            {
                REGBITS_CLR(hI2c->Instance->CR, I2Cx_CR_AA_Msk);
            }
            break;
        }
        case 0x48:                                                    // SLA + R + NAK
        case 0x58:                                                    // Recv DR + NAK
        {
            *hI2c->pBuffPtr = hI2c->Instance->DR;
            hI2c->pBuffPtr++;
            hI2c->XferCount--;
            if (hI2c->XferDone == I2C_XFERDONE_STOP)
            {
                REGBITS_SET(hI2c->Instance->CR, I2Cx_CR_STO_Msk);
                REGBITS_CLR(hI2c->Instance->CR, I2Cx_CR_SI_Msk);
            }
            if (hI2c->Instance == SYM_I2C1)
            {
                NVIC_DisableIRQ(I2C1_IRQn);
            }
            hI2c->XferState = HAL_OK;
            return;
        }
        default:
        {
            hI2c->XferState = HAL_ERROR;
            break;
        }
    }

    REGBITS_CLR(hI2c->Instance->CR, I2Cx_CR_SI_Msk);
}


/*******************************************************************************
  * @brief  查询待通过中断读取的数据是否发送完成
  * @param  hI2c       : I2C句柄指针，指向包含I2C配置、通信参数的结构体
  * @retval HAL status : HAL_OK    表示成功完成接收数据
  *                      HAL_BUSY  表示正在接收数据
  *                      HAL_ERROR 表示接收数据失败，查询I2Cx->STAT以获取失败原因
  */
HAL_StatusTypeDef HAL_I2C_Master_Receive_IT_IsComplete(I2C_HandleTypeDef *hI2c)
{
    return hI2c->XferState;
}


/*******************************************************************************
  * @brief  作为从机，做好传输的准备
  * @param  I2Cx       : I2C模块名称  @arg I2C1
  * @retval None
  */
void HAL_I2C_Slave_Xfer_Init(I2C_TypeDef *I2Cx)
{
    REGBITS_SET(I2Cx->CR, I2Cx_CR_AA_Msk);
}


/*******************************************************************************
  * @brief  作为从机等待被主机选中
  * @param  hI2c       : I2C句柄指针，指向包含I2C配置、通信参数的结构体
  * @param  AccessAddr : 被选中的从机地址指针
  *                      @arg I2C_AccessAddr_0
  *                      @arg I2C_AccessAddr_1
  *                      @arg I2C_AccessAddr_2
  *                      @arg I2C_AccessAddr_GC
  * @param  XferMode   : 输出被选中的操作模式（从机视角）
  *                      @arg I2C_XFERMODE_TRANSMIT: 主机通过读模式选中从机
  *                      @arg I2C_XFERMODE_RECEIVE： 主机通过写模式选中从机
  * @param  TimeOut    : 等待被选中的超时时间，以ms为单位
  *                      0代表一直等待，没有超时功能
  * @retval HAL status : HAL_OK      表示已被主机选中
  *                      HAL_TIMEOUT 表示未被主机选中，等待被主机选中期间TimeOut
  * @note   TimeOut说明: 该函数TimeOut时会强制把从机转换为未寻址状态且关闭寻址应答，直到下一次进入
  *                      该函数时打开寻址应答，因此要注意使用该函数查询时的不应答死区
  */
HAL_StatusTypeDef HAL_I2C_Slave_WaitSelected(I2C_HandleTypeDef *hI2c, uint8_t *AccessAddr, I2C_XferModeTypeDef *XferMode, uint32_t TimeOut)
{
    uint32_t tickStart = HAL_GetTick();

    REGBITS_SET(hI2c->Instance->CR, I2Cx_CR_AA_Msk);                  // 应答阶段回应ACK

    while ((TimeOut == 0) || ((HAL_GetTick() - tickStart) <= TimeOut))
    {
        if (I2C_WaitSIUntilTimeout(hI2c, TimeOut, tickStart) != HAL_OK) // 查询I2C状态
        {
            REGBITS_SET(hI2c->Instance->CR, I2Cx_CR_STO_Msk);
            REGBITS_CLR(hI2c->Instance->CR, I2Cx_CR_AA_Msk);          // 忽略主机寻址
            return HAL_TIMEOUT;
        }

        uint8_t tmp8 = hI2c->Instance->STAT;

        if ((tmp8 == 0x60) || (tmp8 == 0x68) || (tmp8 == 0xA8) || (tmp8 == 0xB0))
        {
           *AccessAddr = hI2c->Instance->MATCH;
           *XferMode   = (tmp8 > 0x68) ? I2C_XFERMODE_TRANSMIT : I2C_XFERMODE_RECEIVE;
           return HAL_OK;
        }

        if ((tmp8 == 0x70) || (tmp8 == 0x78))                         // 通过广播地址选中
        {
           *AccessAddr = I2C_AccessAddr_GC;
           *XferMode   = I2C_XFERMODE_RECEIVE;
           return HAL_OK;
        }

        if (tmp8 == 0x00)                                             // 检测到总线错误
        {
            HAL_I2C_DISABLE(hI2c);                                    // 重启I2C
            HAL_I2C_ENABLE(hI2c);
            REGBITS_SET(hI2c->Instance->CR, I2Cx_CR_AA_Msk);          // 应答阶段回应ACK
            continue;
        }

        REGBITS_CLR(hI2c->Instance->CR, I2Cx_CR_SI_Msk);              // 释放SDA总线，更新I2C状态
    }

    return HAL_TIMEOUT;
}


/*******************************************************************************
  * @brief  作为从机向I2C总线发送一个字节
  * @param  I2Cx       : I2C模块名称  @arg I2C1
  * @param  TxByte     : 待发送到总线的上数据
  * @retval HAL status : HAL_OK    表示向总线发送数据成功
  *                      HAL_ERROR 表示向总线发送数据失败，查询I2Cx->STAT以获取失败原因
  */
HAL_StatusTypeDef HAL_I2C_Slave_SendByte(I2C_TypeDef *I2Cx, uint8_t TxByte)
{
    I2Cx->DR = TxByte;
    REGBITS_CLR(I2Cx->CR, I2Cx_CR_SI_Msk);
    while ((I2Cx->CR & I2Cx_CR_SI_Msk) == 0x00) { ; }                 // 等待发送完成

    if ((I2Cx->STAT == 0xB8) || (I2Cx->STAT == 0xC0))
    {
        return HAL_OK;
    }

    // 从机最后一个字节发送完成后，不应该收到C8。
    return HAL_ERROR;
}


/*******************************************************************************
  * @brief  作为从机从I2C总线接收一个字节并发送ACK/NAK
  * @param  I2Cx       : I2C模块名称  @arg I2C1
  * @param  AckOrNak   : 接收完成后发送到总线上的ACK/NAK
  *                      @arg I2C_RESPONSE_ACK
  *                      @arg I2C_RESPONSE_NAK
  * @retval HAL status : HAL_OK    表示接收数据完成
  *                      HAL_ERROR 表示接收数据失败，查询I2Cx->STAT以获取失败原因
  */
HAL_StatusTypeDef HAL_I2C_Slave_RecvByte(I2C_TypeDef *I2Cx, uint8_t *pRxByte, uint8_t AckOrNak)
{
    REGBITS_MODIFY(I2Cx->CR, I2Cx_CR_AA_Msk, (uint32_t)AckOrNak);
    REGBITS_CLR(I2Cx->CR, I2Cx_CR_SI_Msk);
    while ((I2Cx->CR & I2Cx_CR_SI_Msk) == 0) { ; }

    uint8_t tmp8 = I2Cx->STAT;
    if ((tmp8 == 0x80) || (tmp8 == 0x88) || (tmp8 == 0x90) || (tmp8 == 0x98))
    {
        *pRxByte = I2Cx->DR;
        return HAL_OK;
    }

    return HAL_ERROR;
}


/*******************************************************************************
  * @brief  作为从机采用查询方式向主机发送多个字节
  * @param  hI2c       : I2C句柄指针，指向包含I2C配置、通信参数的结构体
  * @param  pData      : 存储待发送的数据的指针
  * @param  Size       : 传入待发送的数据的数量
  * @param  TimeOut    : 等待发送数据的超时时间，以ms为单位。
  *                      0代表一直等待，没有超时功能
  * @retval HAL status : HAL_OK    表示发送数据到主机成功
  *                      HAL_TIMEOUT 表示发送超时，查询I2Cx->STAT以获取超时原因
  *                      HAL_ERROR 表示发送数据到主机失败，查询I2Cx->STAT以获取失败原因
  */
HAL_StatusTypeDef HAL_I2C_Slave_Transmit(I2C_HandleTypeDef *hI2c, uint8_t *pData, uint32_t Size, uint32_t TimeOut)
{
    uint32_t tickStart = HAL_GetTick();
    I2C_ResponseTypeDef RespAck = I2C_RESPONSE_ACK;

    if (hI2c == NULL)
    {
        return HAL_ERROR;
    }

    hI2c->pBuffPtr   = pData;
    hI2c->XferSize   = Size;
    hI2c->XferCount  = Size;
    hI2c->XferMode   = I2C_XFERMODE_TRANSMIT;
    hI2c->XferState  = HAL_BUSY;
    hI2c->ErrorCode  = I2C_ERROR_OK;

    while (hI2c->XferCount > 0)
    {
        RespAck = (hI2c->XferCount > 1) ? I2C_RESPONSE_ACK : I2C_RESPONSE_NAK;
        REGBITS_MODIFY(hI2c->Instance->CR, I2Cx_CR_AA_Msk, (uint32_t)RespAck);
        hI2c->Instance->DR = *hI2c->pBuffPtr;
        hI2c->XferCount--;
        hI2c->pBuffPtr++;
        REGBITS_CLR(hI2c->Instance->CR, I2Cx_CR_SI_Msk);              // 开始发送

        if (HAL_OK != I2C_WaitSIUntilTimeout(hI2c, TimeOut, tickStart))    // TimeOut等待SI中断标志
        {
            hI2c->ErrorCode = I2C_ERROR_SLAVE_TRANSMIT_TIMEOUT;
            break;
        }
        switch (hI2c->Instance->STAT)
        {
            case 0xB8:                                                // 收到ACK
                continue;
            case 0xC0:
                if (hI2c->XferCount > 0)                              // 发送数据时剩余
                {
                    hI2c->ErrorCode = I2C_ERROR_SLAVE_TRANSMIT_DATA_REMAIN;
                }
                break;
            case 0xC8:                                                // 发送数据时溢出
                if (hI2c->XferCount == 0)
                {
                    hI2c->ErrorCode = I2C_ERROR_SLAVE_TRANSMIT_DATA_OV;
                }
                break;
            case 0xA0:
                hI2c->ErrorCode = I2C_ERROR_SLAVE_RECEIVE_RESTART;    // 接收数据时出现起始或停止信号
                break;
            case 0x00:                                                // 总线错误
                hI2c->ErrorCode = I2C_ERROR_BUS;
                break;
            default:
                hI2c->ErrorCode = I2C_ERROR_SLAVE_STATUS;             // 状态错误
                break;
        }
        if (I2C_ERROR_OK != hI2c->ErrorCode)                          // 检查状态
        {
            break;
        }
    }

    if (I2C_ERROR_OK != hI2c->ErrorCode)
    {
        return HAL_I2C_DealError(hI2c);
    }
    else
    {
        REGBITS_CLR(hI2c->Instance->CR, I2Cx_CR_AA_Msk);              // 不回应ACK
        REGBITS_CLR(hI2c->Instance->CR, I2Cx_CR_SI_Msk);              // 释放SDA总线，更新I2C状态
        hI2c->XferState = HAL_OK;
        return HAL_OK;
    }
}


/*******************************************************************************
  * @brief  作为从机采用查询方式从主机接收多个字节
  * @param  hI2c       : I2C句柄指针，指向包含I2C配置、通信参数的结构体
  * @param  pData      : 存储从总线接收到的数据的指针
  * @param  Size       : 待接收的数据的数量
  * @param  TimeOut    : 等待接收数据的超时时间，以ms为单位。
  *                      0代表一直等待，没有超时功能
  * @retval HAL status : HAL_OK    表示Slave设备接收数据成功
  *                      HAL_TIMEOUT 表示接收超时，查询I2Cx->STAT以获取超时原因
  *                      HAL_ERROR 表示Slave设备接收数据失败，查询I2Cx->STAT以获取失败原因
  */
HAL_StatusTypeDef HAL_I2C_Slave_Receive(I2C_HandleTypeDef *hI2c, uint8_t *pData, uint32_t Size, uint32_t TimeOut)
{
    uint32_t tickStart = HAL_GetTick();
    I2C_ResponseTypeDef RespAck = I2C_RESPONSE_ACK;

    if (hI2c == NULL)
    {
        return HAL_ERROR;
    }

    hI2c->pBuffPtr   = pData;
    hI2c->XferSize   = Size;
    hI2c->XferCount  = Size;
    hI2c->XferMode   = I2C_XFERMODE_RECEIVE;
    hI2c->XferState  = HAL_BUSY;
    hI2c->ErrorCode  = I2C_ERROR_OK;

    while (hI2c->XferCount > 0)
    {
        RespAck = (hI2c->XferCount > 1) ? I2C_RESPONSE_ACK : I2C_RESPONSE_NAK;
        REGBITS_MODIFY(hI2c->Instance->CR, I2Cx_CR_AA_Msk, (uint32_t)RespAck);
        REGBITS_CLR(hI2c->Instance->CR, I2Cx_CR_SI_Msk);

        if (HAL_OK != I2C_WaitSIUntilTimeout(hI2c, TimeOut, tickStart)) // TimeOut等待SI中断标志
        {
            hI2c->ErrorCode = I2C_ERROR_SLAVE_RECEIVE_TIMEOUT;
            break;
        }

        switch (hI2c->Instance->STAT)
        {
            case 0x80:
            case 0x90:                                                // 数据已接收，已应答
                *hI2c->pBuffPtr = hI2c->Instance->DR;
                hI2c->XferCount--;
                hI2c->pBuffPtr++;
                continue;
            case 0x88:
            case 0x98:                                                // 数据已接收，未应答
                if (RespAck == I2C_RESPONSE_NAK)
                {
                    *hI2c->pBuffPtr = hI2c->Instance->DR;
                    hI2c->XferCount--;
                    hI2c->pBuffPtr++;
                }
                else
                {
                    hI2c->ErrorCode = I2C_ERROR_SLAVE_STATUS;         // 状态错误
                }
                break;
            case 0xA0:                                                // 收到P或SR信号
                hI2c->ErrorCode = I2C_ERROR_SLAVE_TRANSMIT_DATA_REMAIN;
                break;
            case 0x00:                                                // 总线错误
                hI2c->ErrorCode = I2C_ERROR_BUS;
                break;
            default:                                                  // 状态错误
                hI2c->ErrorCode = I2C_ERROR_SLAVE_STATUS;
                break;
        }
        if (hI2c->ErrorCode != I2C_ERROR_OK)                          // 检查错误
        {
            break;
        }
    }

    // 错误处理
    if (I2C_ERROR_OK != hI2c->ErrorCode)
    {
        return HAL_I2C_DealError(hI2c);
    }
    else
    {
        REGBITS_CLR(hI2c->Instance->CR, I2Cx_CR_AA_Msk);              // 不回应ACK
        REGBITS_CLR(hI2c->Instance->CR, I2Cx_CR_SI_Msk);              // 释放SDA总线，更新I2C状态
        hI2c->XferState = HAL_OK;
        return HAL_OK;
    }
}


/*******************************************************************************
  * @brief  作为从机采用中断方式向主机发送多个字节
  * @param  hI2c       : I2C句柄指针，指向包含I2C配置、通信参数的结构体
  * @param  pData      : 待传输数据的指针
  * @param  Size       : 待传输数据的字节数量
  * @retval None
  * @note   在调用前，需使能NVIC
  */
HAL_StatusTypeDef HAL_I2C_Slave_Transmit_IT(I2C_HandleTypeDef *hI2c, uint8_t *pData, uint32_t Size)
{
    if (hI2c == NULL)
    {
        return HAL_ERROR;
    }

    hI2c->pBuffPtr   = pData;
    hI2c->XferSize   = Size;
    hI2c->XferCount  = Size;
    hI2c->XferMode   = I2C_XFERMODE_TRANSMIT;
    hI2c->XferState  = HAL_BUSY;

    REGBITS_SET(hI2c->Instance->CR, I2Cx_CR_AA_Msk);

    NVIC_ClearPendingIRQ(I2C1_IRQn);
    NVIC_EnableIRQ(I2C1_IRQn);

    return HAL_OK;
}


/*******************************************************************************
  * @brief  作为从机在中断服务程序中响应发送相关中断
  * @param  hI2c       : I2C句柄指针，指向包含I2C配置、通信参数的结构体
  * @retval None
  */
static void HAL_I2C_Slave_Transmit_IT_CallBack(I2C_HandleTypeDef *hI2c)
{
    switch (hI2c->Instance->STAT)
    {
        case 0xA8:                                                    // SLA + R
        case 0xB0:                                                    // SLA + R
        case 0xB8:                                                    // DR  + ACK
        {
            if (hI2c->XferCount > 0)                                  // 数据尚未发送完成
            {
                hI2c->Instance->CR_f.AA = (hI2c->XferCount > 1) ? 1 : 0;
                hI2c->Instance->DR = *hI2c->pBuffPtr;
                hI2c->pBuffPtr++;
                hI2c->XferCount--;
            }
            else
            {
                hI2c->XferState = HAL_ERROR;
            }
            break;
        }
        case 0xC0:                                                    // DR + NACK
        case 0xC8:                                                    // DR + ACK
        {
            hI2c->XferState = HAL_OK;
            break;
        }
        default:
        {
            break;
        }
    }

    REGBITS_CLR(hI2c->Instance->CR, I2Cx_CR_SI_Msk);
}


/*******************************************************************************
  * @brief  作为从机查询通过中断发送的数据是否发送完成
  * @param  hI2c       : I2C句柄指针，指向包含I2C配置、通信参数的结构体
  * @retval HAL status : HAL_OK   : 表示发送数据完成
  *                      HAL_BUSY : 表示正在发送数据
  *                      HAL_ERROR: 表示发送数据失败，查询I2Cx->STAT以获取失败原因
  */
HAL_StatusTypeDef HAL_I2C_Slave_Transmit_IT_IsComplete(I2C_HandleTypeDef *hI2c)
{
    return hI2c->XferState;
}


/*******************************************************************************
  * @brief  作为从机采用中断方式从主机接收多个字节
  * @param  hI2c       : I2C句柄指针，指向包含I2C配置、通信参数的结构体
  * @param  pData      : 待接收数据的指针
  * @param  Size       : 待接收数据的字节数量
  * @retval None
  * @note   在调用前，需使能NVIC
  */
HAL_StatusTypeDef HAL_I2C_Slave_Receive_IT(I2C_HandleTypeDef *hI2c, uint8_t *pData, uint32_t Size)
{
    if (hI2c == NULL)
    {
        return HAL_ERROR;
    }

    hI2c->pBuffPtr   = pData;
    hI2c->XferSize   = Size;
    hI2c->XferCount  = Size;
    hI2c->XferMode   = I2C_XFERMODE_RECEIVE;
    hI2c->XferState  = HAL_BUSY;

    REGBITS_SET(hI2c->Instance->CR, I2Cx_CR_AA_Msk);

    NVIC_ClearPendingIRQ(I2C1_IRQn);
    NVIC_EnableIRQ(I2C1_IRQn);

    return HAL_OK;
}


/*******************************************************************************
  * @brief  作为从机在中断服务程序中响应接收相关中断
  * @param  hI2c       : I2C句柄指针，指向包含I2C配置、通信参数的结构体
  * @retval None
  */
static void HAL_I2C_Slave_Receive_IT_CallBack(I2C_HandleTypeDef *hI2c)
{
    switch (hI2c->Instance->STAT)
    {
        case 0x60:                                                    // SLA+W
        case 0x68:                                                    // SLA+W
        case 0x70:
        case 0x78:
        {
            break;
        }
        case 0xA0:                                                    // Start / Stop
        {
            REGBITS_SET(hI2c->Instance->CR, I2Cx_CR_AA_Msk);
            hI2c->XferState = HAL_OK;
            break;
        }
        case 0x88:                                                    // Recv DR + NAK
        case 0x98:
        {
            hI2c->XferState = HAL_OK;
            // 88状态不需要Break
        }
        case 0x80:                                                    // Recv DR + ACK
        case 0x90:
        {
            *hI2c->pBuffPtr = hI2c->Instance->DR;
            hI2c->pBuffPtr++;
            hI2c->XferCount--;
            hI2c->Instance->CR_f.AA = (hI2c->XferCount > 0) ? 1 : 0;
            if (hI2c->XferCount == 0)
            {
                hI2c->XferState = HAL_OK;
            }
            break;
        }
        default:
        {
            hI2c->XferState = HAL_ERROR;
            break;
        }
    }
    REGBITS_CLR(hI2c->Instance->CR, I2Cx_CR_SI_Msk);
}


/*******************************************************************************
  * @brief  查询待通过中断接收的数据是否接收完成
  * @param  hI2c       : I2C句柄指针，指向包含I2C配置、通信参数的结构体
  * @retval HAL status : HAL_OK    表示接收数据完成
  *                      HAL_BUSY  表示正在接收数据
  *                      HAL_ERROR 表示接收数据失败，查询I2Cx->STAT以获取失败原因
  */
HAL_StatusTypeDef HAL_I2C_Slave_Receive_IT_IsComplete(I2C_HandleTypeDef *hI2c)
{
    return hI2c->XferState;
}


/*******************************************************************************
  * @brief  在中断服务程序中发送并接收I2C数据
  * @param  hI2c       : I2C句柄指针，指向包含I2C配置、通信参数的结构体
  * @retval None
  * @note   需要在I2Cx的中断服务程序中调用 HAL_SPI_IRQHandler 函数
  *         在调用前，需使能NVIC
  */
void HAL_I2C_IRQHandler(I2C_HandleTypeDef *hI2c)
{
    if (hI2c->Init.WorkMode == I2C_WORKMODE_MASTER)
    {
        if (hI2c->XferMode == I2C_XFERMODE_TRANSMIT)
        {
            HAL_I2C_Master_Transmit_IT_CallBack(hI2c);
        }
        else
        {
            HAL_I2C_Master_Receive_IT_CallBack(hI2c);
        }
    }
    else
    {
        if (hI2c->XferMode == I2C_XFERMODE_TRANSMIT)
        {
            HAL_I2C_Slave_Transmit_IT_CallBack(hI2c);
        }
        else
        {
            HAL_I2C_Slave_Receive_IT_CallBack(hI2c);
        }
    }
}


/************************ (C) COPYRIGHT SIYIMicro *****END OF FILE*************/
